<template>
    <div class="container">
        <div v-if="propJson.uploadType === 'button'" style="margin-bottom: 3%">
            <label :class="propJson.editFlag ? 'editFileComponentButtonClass' : 'fileComponentButtonClass'">
                    <span class="fileComponentSpanClass" :style="execButtonSpanStyle">
                        <component is="UploadOutlined" style="margin-right: 1%"/>
                        上传
                    </span>
                <input type="file" class="fileInput" @change="changeFn">
            </label>
        </div>

        <div v-if="propJson.uploadType === 'icon'" style="margin-bottom: 3%">
            <label :class="propJson.editFlag ? 'editFileComponentIconClass' : 'fileComponentIconClass'" :style="execIconLabel">
                <span :style="execIconSpan" style="display: flex; align-items: center; justify-content: center">
                    <div style="">
                        <component is="PlusOutlined" :style="execIconComponent"/>
                        <span :style="execIconTipSpan">
                            点击上传文件
                        </span>
                    </div>
                </span>
                <input type="file" class="fileInput" @change="changeFn">
            </label>
        </div>

        <div v-if="percentageFlag" style="width: 100%; margin-bottom: 3%">
            <el-progress :percentage="percentageNum" :status="percentageStatus"/>
        </div>
    </div>
</template>

<script>
import {deepCopy, setJsonValue} from "@/utils/tagCreate";
import {doUploadApi, getBuildParam} from "@/request/lowcode/thirdService";
import {ElMessage, ElNotification} from "element-plus";

export default {
    name: "FileUploadMultiComponent",
    props: ['propJson', 'commonParam'],
    data() {
        return {
            percentageFlag: false,
            percentageNum: 0,
            percentageStatus: ''
        }
    },
    methods: {
        splitFile(partNum, file) {
            const partFiles = [];
            let sliceFileIndex = 0;
            let realPartSize = this.realPartSize
            for (let index = 0; index < partNum; index++) {
                partFiles.push(file.slice(sliceFileIndex, sliceFileIndex + realPartSize));
                sliceFileIndex += realPartSize;
            }
            return partFiles;
        },
        execCatch(error) {
            ElMessage({
                message: '上传失败',
                type: 'error',
            })
            this.percentageStatus = 'exception'
        },
        finishThen() {
            ElMessage({
                message: '上传完成',
                type: 'success',
            })
            this.percentageStatus = 'success'
        },
        async changeFn(e) {
            // 进度条重置为0
            this.percentageFlag = true
            this.percentageNum = 0;
            // 获取待上传的文件
            const file = e.target.files[0];
            const fileName = file.name;
            // 分段数
            let realPartSize = this.realPartSize
            const partNum = Math.ceil(file.size / realPartSize);
            // 切割分段文件
            const partFiles = this.splitFile(partNum, file);
            // 记录全局请求变量信息
            let globalRequestParam = []
            // 执行上传前置请求
            await this.doUploadBeforeAction(fileName, partNum, globalRequestParam);
            // 弹出提示框
            ElNotification({
                title: '提示',
                message: "文件上传中，请勿刷新页面！！",
                type: 'Warning',
            });
            // 执行上传文件方法
            await this.doUploadAction(fileName, partNum, globalRequestParam, partFiles);
            // 执行上传文件校验方法
            await this.doUploadCheckAction(fileName, partNum, globalRequestParam, partFiles);
            // 执行上传文件合并方法
            await this.doUploadMergeAction(fileName, partNum, globalRequestParam);
        },
        async doUploadBeforeAction(fileName, partNum, globalRequestParam) {
            // 根据配置的内置参数映射为全局变量中的字段
            let beforeActionRequestVariable = this.propJson.doUploadBeforeActionInnerRequestVariable;
            // 多个内置变量挨个处理  构建参数
            let beforeAction = deepCopy(this.propJson.doUploadBeforeAction)
            let partNumRequestVariable = beforeActionRequestVariable[0]
            if (partNumRequestVariable.variableName) {
                let tempVariableInfo = {variableName: beforeActionRequestVariable[0].variableName, variableValue: partNum, type: "custom", variableType: "String", variableParamName: ""}
                beforeAction.apiParamList.push(tempVariableInfo)
            }
            let fileNameRequestVariable = beforeActionRequestVariable[1]
            if (fileNameRequestVariable.variableName) {
                let tempVariableInfo = {variableName: beforeActionRequestVariable[1].variableName, variableValue: fileName, type: "custom", variableType: "String", variableParamName: ""}
                beforeAction.apiParamList.push(tempVariableInfo)
            }
            let res = await doUploadApi(beforeAction, this.commonParam, () => {}, this.execCatch, {}, {}, false)
            for (let objName in res) {
                let prop = res[objName]
                if (objName.startsWith("$.")) {
                    setJsonValue(globalRequestParam, objName, prop)
                } else {
                    globalRequestParam[objName] = prop
                }
            }
        },
        async doUploadAction(fileName, partNum, globalRequestParam, partFiles) {
            // 此变量用作计算进度百分比
            let currentDoIndex = 1;
            // 遍历所有分段文件，挨个上传
            for (let index = 0; index < partNum; index++) {
                let formData = this.getFormDataInfo(index, partFiles, partNum, fileName, globalRequestParam);
                let res = await doUploadApi(this.propJson.doUploadAction, this.commonParam, () => {}, this.execCatch, {}, formData, true)
                // 接收返参
                for (let objName in res) {
                    let prop = res[objName]
                    if (objName.startsWith("$.")) {
                        setJsonValue(globalRequestParam, objName, prop)
                    } else {
                        globalRequestParam[objName] = prop
                    }
                }
                // 计算进度
                this.percentageNum = (currentDoIndex / partNum * 100).toFixed(2);
                currentDoIndex += 1;
            }
        },
        async doUploadCheckAction(fileName, partNum, globalRequestParam, partFiles) {
            // 未配置参数，直接放行
            if (!this.propJson.doUploadCheckAction.apiPath) {
                return;
            }
            let level = 0
            while (level < this.propJson.maxCheckLevel) {
                // 根据配置的内置参数映射为全局变量中的字段
                let uploadCheckActionRequestVariable = this.propJson.doUploadCheckActionInnerRequestVariable;
                // 多个内置变量挨个处理  构建参数
                let checkAction = deepCopy(this.propJson.doUploadCheckAction)
                let partNumRequestVariable = uploadCheckActionRequestVariable[0]
                if (partNumRequestVariable.variableName) {
                    let tempVariableInfo = {variableName: uploadCheckActionRequestVariable[0].variableName, variableValue: partNum, type: "custom", variableType: "String", variableParamName: ""}
                    checkAction.apiParamList.push(tempVariableInfo)
                }
                let fileNameRequestVariable = uploadCheckActionRequestVariable[1]
                if (fileNameRequestVariable.variableName) {
                    let tempVariableInfo = {variableName: uploadCheckActionRequestVariable[1].variableName, variableValue: fileName, type: "custom", variableType: "String", variableParamName: ""}
                    checkAction.apiParamList.push(tempVariableInfo)
                }
                // 构建全局参数
                let realParam = getBuildParam(checkAction, this.commonParam);
                for (let objName in globalRequestParam) {
                    realParam[objName] = globalRequestParam[objName]
                }
                let res = await doUploadApi(checkAction, this.commonParam, () => {}, this.execCatch, {}, realParam, true)
                for (let objName in res) {
                    let prop = res[objName]
                    if (objName.startsWith("$.")) {
                        setJsonValue(globalRequestParam, objName, prop)
                    } else {
                        globalRequestParam[objName] = prop
                    }
                }
                // 返回值必须配置 $.resIds 字段，用于重新上传分段文件内容
                let resIds = globalRequestParam.resIds
                if (resIds && resIds.length > 0) {
                    // 根据返回的异常分段数重新进行上传
                    for (let resIdIndex = 0; resIdIndex < resIds.length; resIdIndex++) {
                        let execIndex = parseInt(resIds[resIdIndex])
                        let formData = this.getFormDataInfo(execIndex, partFiles, partNum, fileName, globalRequestParam);
                        let res = await doUploadApi(this.propJson.doUploadAction, this.commonParam, () => {}, this.execCatch, {}, formData, true)
                        // 接收返参
                        for (let objName in res) {
                            let prop = res[objName]
                            if (objName.startsWith("$.")) {
                                setJsonValue(globalRequestParam, objName, prop)
                            } else {
                                globalRequestParam[objName] = prop
                            }
                        }
                    }
                } else {
                    break;
                }
                level += 1;
            }
        },
        async doUploadMergeAction(fileName, partNum, globalRequestParam) {
            // 未配置参数，直接放行
            if (!this.propJson.doUploadMergeAction.apiPath) {
                return;
            }
            // 根据配置的内置参数映射为全局变量中的字段
            let uploadMergeActionRequestVariable = this.propJson.doUploadMergeActionInnerRequestVariable;
            // 多个内置变量挨个处理  构建参数
            let mergeAction = deepCopy(this.propJson.doUploadMergeAction)
            let partNumRequestVariable = uploadMergeActionRequestVariable[0]
            if (partNumRequestVariable.variableName) {
                let tempVariableInfo = {variableName: uploadMergeActionRequestVariable[0].variableName, variableValue: partNum, type: "custom", variableType: "String", variableParamName: ""}
                mergeAction.apiParamList.push(tempVariableInfo)
            }
            let fileNameRequestVariable = uploadMergeActionRequestVariable[1]
            if (fileNameRequestVariable.variableName) {
                let tempVariableInfo = {variableName: uploadMergeActionRequestVariable[1].variableName, variableValue: fileName, type: "custom", variableType: "String", variableParamName: ""}
                mergeAction.apiParamList.push(tempVariableInfo)
            }
            // 构建全局参数
            let realParam = await getBuildParam(mergeAction, this.commonParam);
            for (let objName in globalRequestParam) {
                realParam[objName] = globalRequestParam[objName]
            }
            let res = await doUploadApi(mergeAction, this.commonParam, this.finishThen, this.execCatch, {}, realParam, true)
            for (let objName in res) {
                let prop = res[objName]
                if (objName.startsWith("$.")) {
                    setJsonValue(globalRequestParam, objName, prop)
                } else {
                    globalRequestParam[objName] = prop
                }
            }
        },
        getFormDataInfo(index, partFiles, partNum, fileName, globalRequestParam) {
            const multiFile = partFiles[index];
            let formData = new FormData();
            // 根据配置的内置参数映射为全局变量中的字段
            let uploadActionRequestVariable = this.propJson.doUploadActionInnerRequestVariable;
            let partNumRequestVariable = uploadActionRequestVariable[0]
            if (partNumRequestVariable.variableName) {
                let variableName = partNumRequestVariable.variableName;
                if (partNumRequestVariable.variableName.startsWith("$.")) {
                    variableName = variableName.substring(2, variableName.length);
                }
                formData.append(variableName.toString(), partNum)
            }
            let multiFileRequestVariable = uploadActionRequestVariable[1]
            if (multiFileRequestVariable.variableName) {
                let variableName = multiFileRequestVariable.variableName;
                if (multiFileRequestVariable.variableName.startsWith("$.")) {
                    variableName = variableName.substring(2, variableName.length);
                }
                formData.append(variableName, multiFile)
            }
            let fileNameRequestVariable = uploadActionRequestVariable[2]
            if (fileNameRequestVariable.variableName) {
                let variableName = fileNameRequestVariable.variableName;
                if (fileNameRequestVariable.variableName.startsWith("$.")) {
                    variableName = variableName.substring(2, variableName.length);
                }
                formData.append(variableName, fileName)
            }
            let segmentIdRequestVariable = uploadActionRequestVariable[3]
            if (segmentIdRequestVariable.variableName) {
                let variableName = segmentIdRequestVariable.variableName;
                if (segmentIdRequestVariable.variableName.startsWith("$.")) {
                    variableName = variableName.substring(2, variableName.length);
                }
                formData.append(variableName, index)
            }
            // 构建全局参数
            for (let objName in globalRequestParam) {
                let prop = globalRequestParam[objName]
                formData.append(objName, prop)
            }
            return formData;
        }
    },
    computed: {
        realPartSize() {
            let partSize = parseInt(this.propJson.partSize);
            let resPartSize = partSize
            let partUnit = this.propJson.partSizeUnit
            if (partUnit === 'b') {
                resPartSize = partSize;
            } else if (partUnit === 'kb') {
                resPartSize = 1024 * partSize;
            } else if (partUnit === 'mb') {
                resPartSize = 1024 * 1024 * partSize;
            }
            return resPartSize;
        },
        execButtonSpanStyle() {
            let style = "";
            if (this.propJson.uploadType !== 'button') {
                return style;
            }
            if (this.propJson.buttonFontSize) {
                style += "font-size: " + this.propJson.buttonFontSize + "px;";
                style += "line-height: " + 2 * parseInt(this.propJson.buttonFontSize) + "px;";
                style += "border-radius: " + parseInt(this.propJson.buttonFontSize) / 3 + "px;";
            }
            return style
        },
        execIconLabel() {
            let style = "";
            if (this.propJson.iconFontHeight) {
                style += "height: " + this.propJson.iconFontHeight + "px;";
                style += "border-radius: " + this.propJson.iconFontHeight / 30 + "px;";
            }
            return style
        },
        execIconSpan() {
            let style = "display: block;";
            if (this.propJson.iconFontHeight) {
                style += "height: " + this.propJson.iconFontHeight + "px;";
            }
            return style
        },
        execIconTipSpan() {
            let style = "display: block;text-align: center;width: 100%;color: #a8abb2;";
            if (this.propJson.iconFontHeight) {
                style += "font-size: " + this.propJson.iconFontHeight / 15 + "px;";
            }
            return style
        },
        execIconComponent() {
            let style = "text-align: center;width: 100%;color: #a8abb2;";
            if (this.propJson.iconFontHeight) {
                style += "font-size: " + this.propJson.iconFontSize + "px;";
            }
            return style
        }
    }
}
</script>

<style scoped lang="less">
.fileInput {
    display: none;
}

.editFileComponentButtonClass {
    width: 90%;
    display: block;
    margin-left: 5%;
    .fileComponentSpanClass {
        width: 100%;
        display: block;
        background-color: #409eff;
        text-align: center;
    }
    .fileComponentSpanClass:hover {
        cursor: pointer;
        background-color: #a0cfff;
    }
    //去除光标
    caret-color: transparent;
}

.fileComponentButtonClass {
    width: 98%;
    display: block;
    padding: 1%;
    .fileComponentSpanClass {
        width: 100%;
        display: block;
        background-color: #409eff;
        text-align: center;
    }
    .fileComponentSpanClass:hover {
        cursor: pointer;
        background-color: #a0cfff;
    }
    //去除光标
    caret-color: transparent;
}

.editFileComponentIconClass {
    width: 90%;
    display: block;
    margin-left: 5%;
    border: 1px dashed #dcdfe6;
    //去除光标
    caret-color: transparent;
}

.fileComponentIconClass {
    width: 98%;
    margin-left: 1%;
    display: block;
    border: 1px dashed #dcdfe6;
    //去除光标
    caret-color: transparent;
}

.fileComponentIconClass:hover {
    cursor: pointer;
    border: 1px dashed #409eff;
}
</style>